﻿using System;
using System.Linq.Expressions;
using System.Web.Mvc;
using System.Web.Mvc.Html;

namespace CodeContrib.Web.Mvc.Html
{
	public static class DisplayExtensions
	{
		public static MvcHtmlString DisplayGroup(this HtmlHelper htmlHelper, string expression)
		{
			return DisplayGroupHelper(htmlHelper, expression, null, null, null);
		}

		public static MvcHtmlString DisplayGroup(this HtmlHelper htmlHelper, string expression, object additionalViewData)
		{
			return DisplayGroupHelper(htmlHelper, expression, null, null, additionalViewData);
		}

		public static MvcHtmlString DisplayGroup(this HtmlHelper htmlHelper, string expression, string templateName)
		{
			return DisplayGroupHelper(htmlHelper, expression, templateName, null, null);
		}

		public static MvcHtmlString DisplayGroup(this HtmlHelper htmlHelper, string expression, string templateName, object additionalViewData)
		{
			return DisplayGroupHelper(htmlHelper, expression, templateName, null, additionalViewData);
		}

		public static MvcHtmlString DisplayGroup(this HtmlHelper htmlHelper, string expression, string templateName, string htmlFieldName)
		{
			return DisplayGroupHelper(htmlHelper, expression, templateName, htmlFieldName, null);
		}

		public static MvcHtmlString DisplayGroup(this HtmlHelper htmlHelper, string expression, string templateName, string htmlFieldName, object additionalViewData)
		{
			return DisplayGroupHelper(htmlHelper, expression, templateName, htmlFieldName, additionalViewData);
		}

		public static MvcHtmlString DisplayGroupFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression)
		{
			return DisplayGroupHelper(htmlHelper, expression, null, null, null);
		}

		public static MvcHtmlString DisplayGroupFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, object additionalViewData)
		{
			return DisplayGroupHelper(htmlHelper, expression, null, null, additionalViewData);
		}

		public static MvcHtmlString DisplayGroupFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, string templateName)
		{
			return DisplayGroupHelper(htmlHelper, expression, templateName, null, null);
		}

		public static MvcHtmlString DisplayGroupFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, string templateName, object additionalViewData)
		{
			return DisplayGroupHelper(htmlHelper, expression, templateName, null, additionalViewData);
		}

		public static MvcHtmlString DisplayGroupFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, string templateName, string htmlFieldName)
		{
			return DisplayGroupHelper(htmlHelper, expression, templateName, htmlFieldName, null);
		}

		public static MvcHtmlString DisplayGroupFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, string templateName, string htmlFieldName, object additionalViewData)
		{
			return DisplayGroupHelper(htmlHelper, expression, templateName, htmlFieldName, additionalViewData);
		}

		internal static MvcHtmlString DisplayGroupHelper(HtmlHelper htmlHelper, string expression, string templateName, string htmlFieldName, object additionalViewData)
		{
			var metadata = ModelMetadata.FromStringExpression(expression, htmlHelper.ViewData);

			if (metadata.DisplayName == null)
			{
				metadata.DisplayName = expression;
			}

			return DisplayGroupHelper(htmlHelper, metadata, templateName, htmlFieldName ?? ExpressionHelper.GetExpressionText(expression), additionalViewData);
		}

		internal static MvcHtmlString DisplayGroupHelper<TModel, TValue>(HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, string templateName, string htmlFieldName, object additionalViewData)
		{
			return DisplayGroupHelper(htmlHelper, ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData), templateName, htmlFieldName ?? ExpressionHelper.GetExpressionText(expression), additionalViewData);
		}

		internal static MvcHtmlString DisplayGroupHelper(HtmlHelper htmlHelper, ModelMetadata metadata, string templateName, string htmlFieldName, object additionalViewData)
		{
			using (htmlHelper.ControlGroup(htmlFieldName))
			{
				var label = new TagBuilder("span");
				label.AddCssClass("control-label");
				label.SetInnerText(metadata.GetDisplayName());

				htmlHelper.ViewContext.Writer.Write(label);

				var display = htmlHelper.Display(htmlFieldName, templateName, additionalViewData).ToHtmlString();

				var controls = new TagBuilder("div")
					               {
						               InnerHtml = display
					               };
				controls.AddCssClass("controls");

				htmlHelper.ViewContext.Writer.Write(controls);
			}

			return MvcHtmlString.Empty;
		}
	}
}